package com.zen.lon.open.remote.metadata;


import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation;

import com.zen.lon.open.proxy.ProxyAgentMetaData;
import com.zen.lon.open.remote.annotation.RemoteClient;
import com.zen.lon.open.remote.exp.RemoteClientException;
import com.zen.lon.open.remote.sign.RemoteInvokeSign;
import com.zen.lon.open.remote.support.ApplicationContextProvider;
import com.zen.lon.open.remote.utils.LogUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

/**
 * 代理类元数据信息
 *
 * @author ZonLen since on 2021/7/9 下午10:22
 */
public class RemoteClientMetadata implements ProxyAgentMetaData {

  private static final String HTTP_PREFIX = "http://";
  private static final String HTTPS_PREFIX = "https://";


  private final Class<?> remoteClientClass;

  private final RestTemplate restTemplate = ApplicationContextProvider
      .getBean("remoteClientRestTemplate", RestTemplate.class);

  private final RemoteClient remoteClient;

  private RemoteInvokeSign remoteInvokeSign;

  public RemoteClientMetadata(Class<?> remoteClientClass) {
    this.remoteClientClass = remoteClientClass;
    this.remoteClient = remoteClientClass.getAnnotation(RemoteClient.class);
    checkProxyClassAnnotation();
  }

  private RemoteInvokeSign initRemoteSignHandler() {
    if (null == this.remoteInvokeSign) {
      final Class<? extends RemoteInvokeSign> signRemoteHeaderHandlerClass = remoteClient
          .remoteSign();
      this.remoteInvokeSign = ApplicationContextProvider
          .getBean(signRemoteHeaderHandlerClass);
    }
    return this.remoteInvokeSign;
  }

  synchronized void signHeader(HttpHeaders headers) {
    initRemoteSignHandler().signHeader(headers);
  }

  /**
   * 请求base地址
   */
  public String baseUrl() {
    final String address = remoteClient.address();
    if (StringUtils.isEmpty(address)) {
      throw new RemoteClientException("@RemoteClient address is not empty");
    }
    String url = ApplicationContextProvider.resolvePlaceholders(address);
    if (StringUtils.isEmpty(url)) {
      throw new RemoteClientException(
          "address key【" + address + "】is not config val, please check");
    }
    if (url.endsWith("/")) {
      url = url.substring(0, url.length() - 1);
    }
    String baseurl;
    if (url.startsWith(HTTP_PREFIX) || url.startsWith(HTTPS_PREFIX)) {
      baseurl = url + processContextPath(remoteClient.serverContextPath());
    } else {
      baseurl = HTTP_PREFIX + url + processContextPath(remoteClient.serverContextPath());
    }
    return baseurl;
  }

  /**
   * context path 地址
   */
  private String processContextPath(String contextPath) {
    if (StringUtils.isEmpty(contextPath)) {
      return "";
    }
    contextPath = ApplicationContextProvider.resolvePlaceholders(contextPath);
    String candidate = StringUtils.trimWhitespace(contextPath);
    if (StringUtils.hasText(candidate) && candidate.endsWith("/")) {
      return candidate.substring(0, candidate.length() - 1);
    }
    return candidate;
  }

  /**
   * 检查提示接口上
   */
  private void checkProxyClassAnnotation() {
    final RequestMapping requestMapping = findMergedAnnotation(remoteClientClass,
        RequestMapping.class);
    if (null != requestMapping) {
      final String[] rootPaths = requestMapping.value();
      LogUtils.error(this.getClass(),
          "{} class annotation @RequestMapping({}) is disable, please remove",
          remoteClientClass.getName(), "\"" + String.join("\",\"", rootPaths) + "\"");
    }
  }

  /**
   * RestTemplate 创建与拦截处理
   */
  RestTemplate restTemplate() {
    return restTemplate;
  }

  public String signUrl(String url) {
    return remoteInvokeSign.signUrl(url);
  }
}
